﻿using System;
using System.Linq;
using NHibernate.Expression;
using System.Collections.Generic;
using Hadlow.Jobvertizer.Common;
using System.Collections;
using System.Text;
using Castle.MonoRail.Framework;

namespace Hadlow.Jobvertizer.Models
{
    public class JobSearchCriteria : IJobSearchCriteria
    {
        string keywords;

        public string Keywords
        {
            get { return keywords; }
            set { keywords = value; }
        }

        Poster poster;

        public Poster Poster
        {
            get { return poster; }
            set { poster = value; }
        }

        Location location;

        public Location Location
        {
            get { return location; }
            set { location = value; }
        }

        Salary salary;

        public Salary Salary
        {
            get { return salary; }
            set { salary = value; }
        }

        public ICriterion[] GetCritera()
        {
            List<ICriterion> criteria = new List<ICriterion>();

            BuildKeywordCriteria(criteria);
            BuildPosterCriteria(criteria);
            BuildSalaryCriteria(criteria);
            BuildLocationCriteria(criteria);

            return criteria.ToArray();
        }

        private void BuildSalaryCriteria(List<ICriterion> criteria)
        {
            if (salary == null) return;
            if (salary.Id != 0) criteria.Add(Expression.Eq("Salary", salary));
        }

        private void BuildPosterCriteria(List<ICriterion> criteria)
        {
            if (poster == null) return;
            if (poster.Id != 0) criteria.Add(Expression.Eq("Poster", poster));
        }

        /// <summary>
        /// Build a keywords expression
        /// </summary>
        /// <param name="criteria"></param>
        private void BuildKeywordCriteria(List<ICriterion> criteria)
        {
            if (!string.IsNullOrEmpty(keywords))
            {
                string[] keywordArray = keywords.Trim().Split(' ');
                foreach (string keyword in keywordArray)
                {
                    string wildcardKeyword = WrapWithWildcard(keyword);
                    ICriterion titleLikeKeyword = Expression.Like("Title", wildcardKeyword);
                    ICriterion descriptionLikeKeyword = Expression.Like("Description", wildcardKeyword);
                    criteria.Add(Expression.Or(titleLikeKeyword, descriptionLikeKeyword));
                }
            }
        }

        private string WrapWithWildcard(string keyword)
        {
            return string.Format("%{0}%", keyword);
        }

        private void BuildLocationCriteria(List<ICriterion> criteria)
        {
            if (location == null) return;
            if (location.Parent != null)
            {
                List<object> locations = new List<object>();
                BuildLocations(locations, location);
                criteria.Add(Expression.In("Location", locations));
            }
        }

        private void BuildLocations(List<object> locations, Location location)
        {
            locations.Add(location);
            location.Children.Each(c => BuildLocations(locations, c));
        }

        /// <summary>
        /// Populates the criteria properties from a NameValueCollection such as Request.Params
        /// </summary>
        /// <param name="parameters"></param>
        public void BuildFrom(System.Collections.Specialized.NameValueCollection parameters)
        {
            this.Keywords = parameters["criteria.keywords"];

            if (parameters["criteria.location.id"] != null)
            {
                this.Location = new Location() { Id = int.Parse(parameters["criteria.location.id"]) };
            }

            if (parameters["criteria.poster.id"] != null)
            {
                this.Poster = new Poster() { Id = int.Parse(parameters["criteria.poster.id"]) };
            }

            if (parameters["criteria.salary.id"] != null)
            {
                this.Salary = new Salary() { Id = int.Parse(parameters["criteria.salary.id"]) };
            }
        }

        /// <summary>
        /// Builds a hashtable of the criteria's parameters. This is useful for many of the
        /// Monorail HtmlHelpers.
        /// </summary>
        public IDictionary Parameters 
        {
            get 
            {
                Hashtable parameters = new Hashtable();

                // the keys have to match the input tag ids in JobSearch/default.vm
                if(!string.IsNullOrEmpty(keywords))
                    parameters.Add("criteria.keywords", keywords);
                if(poster != null)
                    parameters.Add("criteria.poster.id", poster.Id);
                if(location != null)
                    parameters.Add("criteria.location.id", location.Id);
                if(salary != null)
                    parameters.Add("criteria.salary.id", salary.Id);

                return parameters;
            }
        }

        /// <summary>
        /// Builds a querystring for a links
        /// </summary>
        public string Querystring
        {
            get
            {
                StringBuilder querystring = new StringBuilder();
                IDictionary parameters = Parameters;
                foreach (string key in parameters.Keys)
                {
                    querystring.AppendFormat("{0}={1}&", key, parameters[key]);
                }
                return querystring.ToString();
            }
        }
    }
}
